"""
风险控制器

负责风险控制和监控
"""

import time
from typing import Dict, List, Any, Optional, Callable
from datetime import datetime, timedelta
from ..core import unified_logger
from ..core.exceptions import RiskControlError


class RiskRule:
    """风险规则基类"""
    
    def __init__(self, name: str, enabled: bool = True):
        self.name = name
        self.enabled = enabled
        self.triggered_count = 0
        self.last_triggered = None
    
    def check(self, context: Dict[str, Any]) -> tuple[bool, str]:
        """
        检查风险规则
        
        Args:
            context: 风险检查上下文
            
        Returns:
            (是否触发, 触发原因)
        """
        raise NotImplementedError
    
    def on_triggered(self, reason: str):
        """规则触发时的回调"""
        self.triggered_count += 1
        self.last_triggered = datetime.now()


class MaxPositionRule(RiskRule):
    """最大仓位规则"""
    
    def __init__(self, max_position_ratio: float = 0.8):
        super().__init__("最大仓位控制")
        self.max_position_ratio = max_position_ratio
    
    def check(self, context: Dict[str, Any]) -> tuple[bool, str]:
        if not self.enabled:
            return False, ""
        
        total_equity = context.get('total_equity', 0)
        total_position_value = context.get('total_position_value', 0)
        
        if total_equity <= 0:
            return False, ""
        
        position_ratio = total_position_value / total_equity
        
        if position_ratio > self.max_position_ratio:
            reason = f"总仓位比例 {position_ratio:.2%} 超过限制 {self.max_position_ratio:.2%}"
            return True, reason
        
        return False, ""


class SinglePositionRule(RiskRule):
    """单个仓位规则"""
    
    def __init__(self, max_single_position_ratio: float = 0.2):
        super().__init__("单个仓位控制")
        self.max_single_position_ratio = max_single_position_ratio
    
    def check(self, context: Dict[str, Any]) -> tuple[bool, str]:
        if not self.enabled:
            return False, ""
        
        total_equity = context.get('total_equity', 0)
        positions = context.get('positions', {})
        
        if total_equity <= 0:
            return False, ""
        
        for symbol, position in positions.items():
            position_value = position.get('value', 0)
            position_ratio = position_value / total_equity
            
            if position_ratio > self.max_single_position_ratio:
                reason = f"{symbol} 仓位比例 {position_ratio:.2%} 超过限制 {self.max_single_position_ratio:.2%}"
                return True, reason
        
        return False, ""


class DailyLossRule(RiskRule):
    """日亏损规则"""
    
    def __init__(self, max_daily_loss_ratio: float = 0.1):
        super().__init__("日亏损控制")
        self.max_daily_loss_ratio = max_daily_loss_ratio
        self.daily_start_equity = None
        self.last_reset_date = None
    
    def check(self, context: Dict[str, Any]) -> tuple[bool, str]:
        if not self.enabled:
            return False, ""
        
        current_equity = context.get('total_equity', 0)
        current_date = datetime.now().date()
        
        # 重置每日起始权益
        if self.last_reset_date != current_date:
            self.daily_start_equity = current_equity
            self.last_reset_date = current_date
            return False, ""
        
        if self.daily_start_equity is None or self.daily_start_equity <= 0:
            return False, ""
        
        daily_pnl = current_equity - self.daily_start_equity
        daily_loss_ratio = -daily_pnl / self.daily_start_equity
        
        if daily_pnl < 0 and daily_loss_ratio > self.max_daily_loss_ratio:
            reason = f"日亏损比例 {daily_loss_ratio:.2%} 超过限制 {self.max_daily_loss_ratio:.2%}"
            return True, reason
        
        return False, ""


class DrawdownRule(RiskRule):
    """回撤规则"""
    
    def __init__(self, max_drawdown_ratio: float = 0.15):
        super().__init__("最大回撤控制")
        self.max_drawdown_ratio = max_drawdown_ratio
        self.peak_equity = 0
    
    def check(self, context: Dict[str, Any]) -> tuple[bool, str]:
        if not self.enabled:
            return False, ""
        
        current_equity = context.get('total_equity', 0)
        
        # 更新峰值
        if current_equity > self.peak_equity:
            self.peak_equity = current_equity
        
        if self.peak_equity <= 0:
            return False, ""
        
        drawdown = (self.peak_equity - current_equity) / self.peak_equity
        
        if drawdown > self.max_drawdown_ratio:
            reason = f"回撤比例 {drawdown:.2%} 超过限制 {self.max_drawdown_ratio:.2%}"
            return True, reason
        
        return False, ""


class OrderFrequencyRule(RiskRule):
    """订单频率规则"""
    
    def __init__(self, max_orders_per_minute: int = 10):
        super().__init__("订单频率控制")
        self.max_orders_per_minute = max_orders_per_minute
        self.order_timestamps = []
    
    def check(self, context: Dict[str, Any]) -> tuple[bool, str]:
        if not self.enabled:
            return False, ""
        
        current_time = time.time()
        
        # 清理1分钟前的记录
        self.order_timestamps = [
            ts for ts in self.order_timestamps 
            if current_time - ts <= 60
        ]
        
        if len(self.order_timestamps) >= self.max_orders_per_minute:
            reason = f"1分钟内订单数量 {len(self.order_timestamps)} 超过限制 {self.max_orders_per_minute}"
            return True, reason
        
        return False, ""
    
    def record_order(self):
        """记录订单时间"""
        self.order_timestamps.append(time.time())


class PriceDeviationRule(RiskRule):
    """价格偏离规则"""
    
    def __init__(self, max_deviation_ratio: float = 0.05):
        super().__init__("价格偏离控制")
        self.max_deviation_ratio = max_deviation_ratio
    
    def check(self, context: Dict[str, Any]) -> tuple[bool, str]:
        if not self.enabled:
            return False, ""
        
        order_price = context.get('order_price')
        market_price = context.get('market_price')
        
        if not order_price or not market_price or market_price <= 0:
            return False, ""
        
        deviation = abs(order_price - market_price) / market_price
        
        if deviation > self.max_deviation_ratio:
            reason = f"订单价格偏离市价 {deviation:.2%} 超过限制 {self.max_deviation_ratio:.2%}"
            return True, reason
        
        return False, ""


class RiskController:
    """风险控制器"""
    
    def __init__(self, config: Dict[str, Any]):
        """
        初始化风险控制器
        
        Args:
            config: 风险控制配置
        """
        self.config = config
        self.logger = unified_logger.get_logger('risk_controller')
        
        # 风险规则
        self.rules: List[RiskRule] = []
        self.enabled = config.get('enabled', True)
        
        # 回调函数
        self.on_risk_triggered: Optional[Callable] = None
        
        # 统计信息
        self.total_checks = 0
        self.total_triggers = 0
        
        # 初始化规则
        self._init_rules()
        
        self.logger.info("风险控制器初始化完成")
    
    def _init_rules(self):
        """初始化风险规则"""
        # 最大仓位规则
        max_position_ratio = self.config.get('max_total_position_ratio', 0.8)
        self.rules.append(MaxPositionRule(max_position_ratio))
        
        # 单个仓位规则
        max_single_ratio = self.config.get('max_single_position_ratio', 0.2)
        self.rules.append(SinglePositionRule(max_single_ratio))
        
        # 日亏损规则
        max_daily_loss = self.config.get('max_daily_loss_ratio', 0.1)
        self.rules.append(DailyLossRule(max_daily_loss))
        
        # 回撤规则
        max_drawdown = self.config.get('max_drawdown_ratio', 0.15)
        self.rules.append(DrawdownRule(max_drawdown))
        
        # 订单频率规则
        max_orders = self.config.get('max_orders_per_minute', 10)
        self.rules.append(OrderFrequencyRule(max_orders))
        
        # 价格偏离规则
        max_deviation = self.config.get('max_price_deviation_ratio', 0.05)
        self.rules.append(PriceDeviationRule(max_deviation))
    
    def check_position_risk(self, account_info: Dict[str, Any]) -> bool:
        """
        检查仓位风险
        
        Args:
            account_info: 账户信息
            
        Returns:
            是否通过风险检查
        """
        if not self.enabled:
            return True
        
        context = {
            'total_equity': account_info.get('total_equity', 0),
            'total_position_value': account_info.get('total_position_value', 0),
            'positions': account_info.get('positions', {})
        }
        
        return self._check_rules(context, ['最大仓位控制', '单个仓位控制'])
    
    def check_trading_risk(self, account_info: Dict[str, Any]) -> bool:
        """
        检查交易风险
        
        Args:
            account_info: 账户信息
            
        Returns:
            是否通过风险检查
        """
        if not self.enabled:
            return True
        
        context = {
            'total_equity': account_info.get('total_equity', 0)
        }
        
        return self._check_rules(context, ['日亏损控制', '最大回撤控制'])
    
    def check_order_risk(self, order_info: Dict[str, Any]) -> bool:
        """
        检查订单风险
        
        Args:
            order_info: 订单信息
            
        Returns:
            是否通过风险检查
        """
        if not self.enabled:
            return True
        
        context = {
            'order_price': order_info.get('price'),
            'market_price': order_info.get('market_price')
        }
        
        # 检查价格偏离
        passed = self._check_rules(context, ['价格偏离控制'])
        
        # 检查订单频率
        if passed:
            passed = self._check_rules({}, ['订单频率控制'])
            if passed:
                # 记录订单
                for rule in self.rules:
                    if isinstance(rule, OrderFrequencyRule):
                        rule.record_order()
                        break
        
        return passed
    
    def check_all_risks(self, context: Dict[str, Any]) -> bool:
        """
        检查所有风险规则
        
        Args:
            context: 风险检查上下文
            
        Returns:
            是否通过所有风险检查
        """
        if not self.enabled:
            return True
        
        return self._check_rules(context)
    
    def _check_rules(self, context: Dict[str, Any], 
                    rule_names: Optional[List[str]] = None) -> bool:
        """
        检查指定的风险规则
        
        Args:
            context: 检查上下文
            rule_names: 要检查的规则名称列表，None表示检查所有规则
            
        Returns:
            是否通过检查
        """
        self.total_checks += 1
        
        for rule in self.rules:
            if rule_names and rule.name not in rule_names:
                continue
            
            if not rule.enabled:
                continue
            
            try:
                triggered, reason = rule.check(context)
                
                if triggered:
                    self.total_triggers += 1
                    rule.on_triggered(reason)
                    
                    self.logger.warning(f"风险规则触发: {rule.name} - {reason}")
                    
                    # 触发回调
                    if self.on_risk_triggered:
                        try:
                            self.on_risk_triggered(rule.name, reason, context)
                        except Exception as e:
                            self.logger.error(f"风险触发回调执行失败: {e}")
                    
                    return False
                    
            except Exception as e:
                self.logger.error(f"风险规则检查失败 {rule.name}: {e}")
                # 检查失败时保守处理，认为风险触发
                return False
        
        return True
    
    def get_rule_status(self) -> Dict[str, Any]:
        """获取规则状态"""
        rules_status = []
        
        for rule in self.rules:
            rules_status.append({
                'name': rule.name,
                'enabled': rule.enabled,
                'triggered_count': rule.triggered_count,
                'last_triggered': rule.last_triggered.isoformat() if rule.last_triggered else None
            })
        
        return {
            'enabled': self.enabled,
            'total_checks': self.total_checks,
            'total_triggers': self.total_triggers,
            'trigger_rate': self.total_triggers / self.total_checks if self.total_checks > 0 else 0,
            'rules': rules_status
        }
    
    def enable_rule(self, rule_name: str):
        """启用规则"""
        for rule in self.rules:
            if rule.name == rule_name:
                rule.enabled = True
                self.logger.info(f"启用风险规则: {rule_name}")
                return
        
        self.logger.warning(f"未找到风险规则: {rule_name}")
    
    def disable_rule(self, rule_name: str):
        """禁用规则"""
        for rule in self.rules:
            if rule.name == rule_name:
                rule.enabled = False
                self.logger.info(f"禁用风险规则: {rule_name}")
                return
        
        self.logger.warning(f"未找到风险规则: {rule_name}")
    
    def reset_rule_stats(self, rule_name: Optional[str] = None):
        """重置规则统计"""
        if rule_name:
            for rule in self.rules:
                if rule.name == rule_name:
                    rule.triggered_count = 0
                    rule.last_triggered = None
                    self.logger.info(f"重置风险规则统计: {rule_name}")
                    return
        else:
            for rule in self.rules:
                rule.triggered_count = 0
                rule.last_triggered = None
            
            self.total_checks = 0
            self.total_triggers = 0
            self.logger.info("重置所有风险规则统计")
    
    def set_risk_callback(self, callback: Callable[[str, str, Dict[str, Any]], None]):
        """设置风险触发回调函数"""
        self.on_risk_triggered = callback
        self.logger.info("设置风险触发回调函数")
    
    def emergency_stop(self, reason: str):
        """紧急停止"""
        self.logger.critical(f"紧急停止触发: {reason}")
        
        if self.on_risk_triggered:
            try:
                self.on_risk_triggered("紧急停止", reason, {})
            except Exception as e:
                self.logger.error(f"紧急停止回调执行失败: {e}")
        
        raise RiskControlError(f"紧急停止: {reason}")
    
    def get_risk_summary(self) -> str:
        """获取风险摘要报告"""
        status = self.get_rule_status()
        
        report = f"""
=== 风险控制摘要 ===
状态: {'启用' if status['enabled'] else '禁用'}
总检查次数: {status['total_checks']}
总触发次数: {status['total_triggers']}
触发率: {status['trigger_rate']:.2%}

规则状态:
"""
        
        for rule in status['rules']:
            enabled_str = '启用' if rule['enabled'] else '禁用'
            last_triggered = rule['last_triggered'] or '从未'
            
            report += f"  {rule['name']}: {enabled_str}, 触发{rule['triggered_count']}次, 最后触发: {last_triggered}\n"
        
        return report